Saturday afternoon unexpected fun adventure

Bon, je reconnais, j'ai pas été méga-sérieuse. J'ai essayé d'aller à fond sur le développement de [hablo](https://git.marvid.fr/Tissevert/hablo) pour qu'il soit utilisable rapidement et pouvoir ouvrir (enfin !) ce blog. Et de fait j'ai un truc qui marche. Mais. Mais j'ai pas écrit la doc au fur et à mesure. Oui, je m'en mords les doigts, oui je bats ma coulpe. Pas la peine d'en rajouter en me conspuant.

![Une jeune fille qui pleure son oiseau mort](/media/2019/03/jfqpsom.png)

J'ai donc entamé la fin de semaine avec l'espoir déraisonnable que j'allais pouvoir écrire ma doc vite-fait, faire la première release et écrire un joli article là-dessus pour expliquer un peu comment c'était foutu, ce qu'on pouvait faire avec, vous donner envie de l'utiliser, même, pourquoi pas ? Las ! C'était sans compter sans le monde merveilleux de la gestion de version et de l'intégration continue.

Comme je suis une aspirante thésarde bien dressée, j'ai commencé par faire de la biblio et essayer d'apprendre des choses sur la documentation. J'ai appris l'existence du RDD (README-driven development, vous trouvez pas qu'on est fort·es quand même pour trouver des noms classes dans l'industrie logicielle ?) et on m'a aussi dirigée vers cette [ressource](https://www.divio.com/blog/documentation/) (merci, [@eliotberriot](https://mastodon.eliotberriot.com/@eliotberriot)[^subtoot] !) très bien faite et qui m'a fait comprendre que j'avais du boulot.

Je m'y suis mise sans trop renacler mais assez rapidement je me suis rendue compte que la doc devenait assez imposante, surtout maintenant que je savais qu'il fallait que je la découpe en partie avec des buts et des contenus bien distincts. C'est le moment où je me suis rendue compte que [gitea](https://gitea.io/en-us/) fournissait un wiki pour les projets (oui, on utilise gitea pour héberger nos projets). Du coup je me suis dit que c'était parfait et j'ai commencé à créer des pages frénétiquement (enfin j'en ai créé trois, mais en très peu de temps donc c'était quand même pas loin de la frénésie, on va dire une frénésiette).

Et là, comme souvent, le doute m'assaillit. C'est sympa d'avoir des pages comme ça qui flottent mais… c'est pas dans le projet. Tout le monde a pas nécessairement envie de passer son temps sur la page web du projet, ce serait quand même ~~sympa~~ important que la doc soit avec le code. Sinon, la doc risque en plus d'être désynchronisée avec le code (si on modifie quelque chose qui change un comportement, ou ajoute une option par exemple, c'est essentiel de pouvoir modifier la doc dans le même commit ou au moins sur la même branche, pour que toutes ces modifs arrivent en même temps sur la branche `master`).

C'est à ce moment-là qu'on m'apprend (merci aussi, [@dashie](https://pleroma.otter.sh/dashie) !) qu'en fait le wiki du projet est présenté comme un dépôt `git` à part, et donc modifiable programmatiquement assez facilement. Je me dis que ça va donc être une histoire d'aller dans la partie «Paramètres» puis «Déclencheurs Web» du projet et d'ajouter un petit script qui me copie les fichiers dans ce dépôt et pousse un autre commit avec ces modifs.

![L'écran de réglage des déclencheurs web dans gitea](/media/2019/03/webhooks.png)

Mais ce n'est pas aussi facile. On peut apparemment déclencher un appel à une URL pour faire jouer des API de divers autres outils d'intégration continue autour, mais pas juste écrire un petit script maison pour faire la popotte. Et c'est comme ça que je me retrouve, une fois de plus, à devoir bidouiller un petit `post-receive hook` pour `git` (un script qui va s'exécuter à chaque fois que le dépôt reçoit des `commits`, c'est très pratique).

Le script est relativement simple

```bash
#!/usr/bin/env bash

unset GIT_DIR GIT_WORK_TREE

has_changes()
{
	! git diff-index --quiet HEAD || git ls-files --other --directory --exclude-standard | grep -q '.'
}

commit_message()
{
	cat <<-EOF
	Modified by ${COMMIT_ID:0:5}
	https://git.marvid.fr/Tissevert/hablo/commit/${COMMIT_ID}
	EOF
}

INPUT="$(cat)"
INPUT="${INPUT#* }" # forget the previous commit id
COMMIT_ID="${INPUT%% *}"
INPUT="${INPUT##* }"
BRANCH="${INPUT##refs/heads/}"
if [ "${BRANCH}" = "master" ]
then
	REPOS_BASE="${PWD%.git}"
	REPOS_NAME="${REPOS_BASE##*/}"
	TMP_DIR="$(mktemp -d "/tmp/${REPOS_NAME}-post-receive-hook-XXXX")"
	cd "${TMP_DIR}"
	git clone "${REPOS_BASE}.git"
	git clone "${REPOS_BASE}.wiki.git"
	rsync -a --delete --exclude=.git "${REPOS_NAME}/doc/" "${REPOS_NAME}.wiki/"
	cd "${REPOS_NAME}.wiki"
	if has_changes
	then
		git add .
		git commit -m "$(commit_message)"
		git push
	fi
	cd "${REPOS_BASE}.git"
	rm -rf "${TMP_DIR}"
fi
```

On commence par récupérer l'id du `commit` et le nom de la branche dans le texte passé sur l'entrée standard d'après la [doc](https://git-scm.com/docs/githooks#post-receive). On vérifie que la branche de destination est bien `master` histoire que le wiki reflète exactement l'état de la doc de cette branche. Remplacez par `prod` ou autre si votre branche de référence n'est pas `master`.

On clone ensuite les deux dépôts, on met exactement le contenu du répertoire `doc` dans le dépôt correspondant au wiki (ici encore, c'est un script écrit pour les besoins de hablo, adaptez à votre sauce si vous avez choisi d'appeler directement votre dossier `wiki` ou autre). On commit aveuglément tout ce qui a changé, en rappelant quand même l'identifiant du commit qui est à l'origine de cette modif pour pouvoir retrouver facilement le diff et se rappeler ce qui avait changé dans le code pour justifier cette modification de la doc.

*LE* point important dans tout ça et auquel vous n'avez peut-être pas fait gaffe, c'est la première ligne (non, pas le shebang, je parle de la ligne avec les `unset`). Je me suis arraché les cheveux une bonne partie de l'après-midi à cause de cette bêtise avant de finalement retrouver grâce à [cette page](https://morecode.wordpress.com/2009/01/16/git-hook-caveat/) pourquoi je l'avais mise dans un autre vieux `hook` que j'avais écrit naguère. Ce script est lancé par un processus `git` en train de réceptionner des commits. Il travaille dans un répertoire `git` donné, et pour être sûr que ça se sache et que tout le monde soit bien au courant dans tous les sous-processus qui pourront être amenés à être lancés, il peuple les deux [variables](https://git-scm.com/book/en/v2/Git-Internals-Environment-Variables) `GIT_DIR` et `GIT_WORK_TREE`.

Or, ces deux variables sont la réponse à une question que vous vous êtes peut-être déjà posée : «c'est rigolo de faire des `git status` ou autre, mais à chaque fois je dois être dans le répertoire, si je fais `git status <UN_RÉPERTOIRE>` depuis l'extérieur ça marche pas, pourquoi ??». Et oui, git regarde dans le sous-dossier `.git` du répertoire courant, *ou dans le répertoire contenu dans la variable $GIT_DIR*. Cette variable, c'est le moyen de faire ça, de lancer des commandes `git` vers un répertoire sans être dedans. La première, `GIT_DIR` contient le chemin vers le dossier avec les données propres au dépôt (ce qui est normalement dans le sous-dossier `.git` d'un dépôt non-bare), j'imagine qu'on peut s'en servir pour créer des dépôt en renommant `.git` en ce qu'on veut. La deuxième, `GIT_WORK_TREE` désigne la racine du dépôt lui-même et permet donc de lancer les commandes `git` sans aller dans le répertoire préalablement.

Le rappel piquait un peu. J'espère que ça vous servira aussi, moi je devrais m'en souvenir cette fois.

Ah, oui, et je vais pouvoir écrire la doc de hablo maintenant, vu qu'il paraît que c'est ce que je voulais faire à la base.

----

Le [tableau](http://utpictura18.univ-montp3.fr/GenerateurNotice.php?numnotice=A0386) utilisé est «Une Jeune fille, qui pleure son oiseau mort» de Greuze. Et non, il est pas là pour la coulpe que je bats, il me représente quand j'ai compris que j'allais devoir faire ça au lieu d'écrire la doc de hablo et une fois que j'ai retrouvé cette histoire de variables d'environnement de `git` après deux bonnes heures à tourner en rond.

[^subtoot]: Du coup je sais pas, ça compte comme du subtoot ? Parce qu'il y a mention directe mais comme ça fédère pas alors… ?